#!/usr/bin/env node

/**
 * End-to-end tester for Menu Import V2: upload -> wait validated -> commit
 *
 * Usage:
 *   node scripts/test_v2_import.js [EXCEL_PATH]
 *
 * Requirements:
 *   - Backend server running (mock DB ok)
 *   - IMPORT_V2=true
 *   - scripts/token.txt contains a valid admin Bearer token (string only)
 *   - curl available on system (for multipart upload)
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const axios = require('axios');

async function detectPort(ports) {
  for (const p of ports) {
    try {
      const r = await axios.get(`http://localhost:${p}/health`, { timeout: 1000 });
      if (r.status === 200) return p;
    } catch (_) {}
  }
  return null;
}

function readToken() {
  const tokenFile = path.join(__dirname, 'token.txt');
  if (!fs.existsSync(tokenFile)) {
    throw new Error(`token.txt 不存在: ${tokenFile}`);
  }
  const token = fs.readFileSync(tokenFile, 'utf8').trim();
  if (!token) throw new Error('token.txt 为空');
  return token;
}

async function waitForStatus(port, token, jobId, expected = 'validated', timeoutMs = 30000) {
  const start = Date.now();
  const headers = { Authorization: `Bearer ${token}` };
  while (Date.now() - start < timeoutMs) {
    try {
      const r = await axios.get(`http://localhost:${port}/api/admin/menu-import/v2/jobs/${jobId}`,
        { headers, timeout: 3000 });
      if (r.data && r.data.success && r.data.job) {
        const status = r.data.job.status;
        process.stdout.write(`\r⏳ 任务状态: ${status}       `);
        if (status === expected) {
          console.log('\n✅ 校验已完成');
          return r.data.job;
        }
        if (status === 'failed') {
          console.log('\n❌ 校验失败');
          return r.data.job;
        }
        // 若状态仍为 uploaded 且已经生成错误报告，则认为校验未通过，直接返回避免超时
        if (status === 'uploaded' && r.data.job.error_download_url) {
          console.log('\n❌ 校验未通过（存在错误报告）');
          return r.data.job;
        }
      } else {
        process.stdout.write("\r… 等待任务状态 …    ");
      }
    } catch (e) {
      process.stdout.write("\r… 等待任务状态 …    ");
    }
    await new Promise(r => setTimeout(r, 800));
  }
  throw new Error('等待任务状态超时');
}

(async () => {
  try {
    const ports = [3000, 3001, 3011];
    const port = await detectPort(ports);
    if (!port) {
      console.error('❌ 未检测到运行中的后端');
      process.exit(2);
    }
    console.log('✅ 检测到后端端口:', port);

    const token = readToken();
    console.log('🔑 使用 token，长度:', token.length);

    const excelArg = process.argv[2];
    const defaultExcel = path.join(__dirname, '..', 'tmp', 'menu_v2_valid.xlsx');
    const excelPath = excelArg ? path.resolve(excelArg) : defaultExcel;
    if (!fs.existsSync(excelPath)) {
      console.error('❌ Excel 文件不存在:', excelPath);
      process.exit(3);
    }
    console.log('📄 待上传文件:', excelPath);

    // 1) 上传并触发校验（使用 curl 以避免 multipart 边界问题）
    const url = `http://localhost:${port}/api/admin/menu-import/v2/validate`;
    const mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
    const cmd = `curl -sS -H "Authorization: Bearer ${token}" -F "file=@${excelPath};type=${mime}" ${url}`;
    console.log('🚀 开始上传并校验 ...');
    let uploadOut;
    try {
      uploadOut = execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
    } catch (e) {
      console.error('❌ 上传请求失败，stderr:', e.stderr?.toString?.() || e.message);
      process.exit(4);
    }

    let uploadJson;
    try {
      uploadJson = JSON.parse(uploadOut);
    } catch (e) {
      console.error('❌ 解析上传响应失败，原始输出如下:\n', uploadOut);
      process.exit(5);
    }

    if (!uploadJson.success) {
      console.error('❌ 校验接口返回失败:', uploadJson);
      if (uploadJson.message && uploadJson.message.includes('上传频率过高')) {
        console.error('⚠️ 命中频率限制，请等待15分钟或调整 rate-limit 再试');
      }
      process.exit(6);
    }

    const jobId = uploadJson.job_id;
    if (!jobId) {
      console.error('❌ 未返回 job_id:', uploadJson);
      process.exit(7);
    }
    console.log('🆔 任务ID:', jobId);

    // 1.5) 立即检查响应中的 validation_result，若失败则直接输出并退出
    if (uploadJson.validation_result && uploadJson.validation_result.success === false) {
      console.error('❌ 校验未通过（立即结果）');
      const headers = { Authorization: `Bearer ${token}` };
      try {
        const r = await axios.get(`http://localhost:${port}/api/admin/menu-import/v2/jobs/${jobId}`, { headers, timeout: 5000 });
        if (r.data?.job?.error_download_url) {
          console.error('📎 验证报告下载:', `http://localhost:${port}${r.data.job.error_download_url}`);
        }
      } catch (_) {}
      process.exit(8);
    }

    // 2) 轮询等待校验状态 validated/failed，或检测到错误报告
    const job = await waitForStatus(port, token, jobId, 'validated', 30000);
    if (job.status !== 'validated') {
      console.error('❌ 任务未通过校验:', job.status);
      if (job.error_download_url) {
        console.error('📎 验证报告下载:', `http://localhost:${port}${job.error_download_url}`);
      }
      process.exit(8);
    }

    // 3) 提交 commit
    console.log('📦 开始提交 ...');
    let commitRes;
    try {
      commitRes = await axios.post(
        `http://localhost:${port}/api/admin/menu-import/v2/commit`,
        null,
        {
          params: { job_id: jobId },
          headers: { Authorization: `Bearer ${token}` },
          timeout: 20000
        }
      );
    } catch (e) {
      const data = e.response ? e.response.data : e.message;
      console.error('❌ 提交请求失败:', data);
      process.exit(9);
    }

    console.log('✅ 提交成功:', JSON.stringify(commitRes.data, null, 2));
  } catch (err) {
    console.error('❌ 脚本执行失败:', err.message || err);
    process.exit(1);
  }
})();